package com.javaforever.gatescore.tool;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.javaforever.gatescore.core.PluralUtil;
import org.javaforever.gatescore.utils.StringUtil;

public class FakeDomain implements Comparable<FakeDomain>{
	protected String domainName;
	protected String domainIdName;
	protected String domainNameName;
	protected String domainActiveName;
	protected String domainToken;
	protected String domainNamingSuffix;
	protected Set<String> fields = new TreeSet<>();
	@Override
	public int compareTo(FakeDomain o) {
		return this.domainName.compareTo(o.getDomainName());
	}
	public String getDomainName() {
		return domainName;
	}
	public void setDomainName(String domainName) {
		this.domainName = domainName;
	}
	public String getDomainIdName() {
		return domainIdName;
	}
	public void setDomainIdName(String domainIdName) {
		this.domainIdName = domainIdName;
	}
	public String getDomainNameName() {
		return domainNameName;
	}
	public void setDomainNameName(String domainNameName) {
		this.domainNameName = domainNameName;
	}
	public String getDomainActiveName() {
		return domainActiveName;
	}
	public void setDomainActiveName(String domainActiveName) {
		this.domainActiveName = domainActiveName;
	}
	public Set<String> getFields() {
		return fields;
	}
	public void setFields(Set<String> fields) {
		this.fields = fields;
	}
	public String getDomainToken() {
		return domainToken;
	}
	public void setDomainToken(String domainToken) {
		this.domainToken = domainToken;
	}
	public String getDomainNamingSuffix() {
		return domainNamingSuffix;
	}
	public void setDomainNamingSuffix(String domainNamingSuffix) {
		this.domainNamingSuffix = domainNamingSuffix;
	}
	
	public String matches(String token) {
		if (StringUtil.isBlank(token)) return null;
		if (!StringUtil.isBlank(this.domainName)&&token.equals(StringUtil.capFirst(this.domainName))) return "capFirstDomainName";
		if (!StringUtil.isBlank(this.domainName)&&token.equals(StringUtil.lowerFirst(this.domainName))) return "lowerFirstDomainName";
		if (!StringUtil.isBlank(this.domainName)&&token.equals(StringUtil.capFirst(PluralUtil.lookupPlural(this.domainName)))) return "capFirstDomainPlural";
		if (!StringUtil.isBlank(this.domainName)&&token.equals(StringUtil.lowerFirst(PluralUtil.lookupPlural(this.domainName)))) return "lowerFirstDomainPlural";
		if (!StringUtil.isBlank(this.domainName)&&!StringUtil.isBlank(this.domainNamingSuffix)&&token.equals(StringUtil.capFirst(this.domainName)+StringUtil.capFirst(this.domainNamingSuffix))) return "capFirstDomainNameWithSuffix";
		if (!StringUtil.isBlank(this.domainName)&&!StringUtil.isBlank(this.domainNamingSuffix)&&token.equals(StringUtil.lowerFirst(this.domainName)+StringUtil.capFirst(this.domainNamingSuffix))) return "lowerFirstDomainNameWithSuffix";
		if (!StringUtil.isBlank(this.domainIdName)&&token.equals(StringUtil.capFirst(this.domainIdName))) return "capFirstDomainIdName";
		if (!StringUtil.isBlank(this.domainIdName)&&token.equals(StringUtil.lowerFirst(this.domainIdName))) return "lowerFirstDomainIdName";
		if (!StringUtil.isBlank(this.domainNameName)&&token.equals(StringUtil.capFirst(this.domainNameName))) return "capFirstDomainNameName";
		if (!StringUtil.isBlank(this.domainNameName)&&token.equals(StringUtil.lowerFirst(this.domainNameName))) return "lowerFirstDomainNameName";
		if (!StringUtil.isBlank(this.domainActiveName)&&token.equals(StringUtil.capFirst(this.domainActiveName))) return "capFirstDomainActiveName";
		if (!StringUtil.isBlank(this.domainActiveName)&&token.equals(StringUtil.lowerFirst(this.domainActiveName))) return "lowerFirstDomainActiveName";
		for (String field:this.fields) {
			if (!StringUtil.isBlank(field)&&token.equals(StringUtil.capFirst(field))) return "capFirstField:"+field;
			if (!StringUtil.isBlank(field)&&token.equals(StringUtil.lowerFirst(field))) return "lowerFirstField:"+field;
		}
		return null;
	}
	
	public String matchedToken(String name) {
		switch (name) {
			case "capFirstDomainName":
				return StringUtil.capFirst(this.domainName);
			case "lowerFirstDomainName":
				return StringUtil.lowerFirst(this.domainName);
			case "capFirstDomainPlural":
				return StringUtil.capFirst(PluralUtil.lookupPlural(this.domainName));
			case "lowerFirstDomainPlural":
				return StringUtil.lowerFirst(PluralUtil.lookupPlural(this.domainName));
			case "capFirstDomainNameWithSuffix":
				return StringUtil.capFirst(this.domainName)+StringUtil.capFirst(this.domainNamingSuffix);
			case "lowerFirstDomainNameWithSuffix":
				return StringUtil.lowerFirst(this.domainName)+StringUtil.capFirst(this.domainNamingSuffix);
			case "capFirstDomainIdName":
				return StringUtil.capFirst(this.domainIdName);
			case "lowerFirstDomainIdName":
				return StringUtil.lowerFirst(this.domainIdName);
			case "capFirstDomainNameName":
				return StringUtil.capFirst(this.domainNameName);
			case "lowerFirstDomainNameName":
				return StringUtil.lowerFirst(this.domainNameName);
			case "capFirstDomainActiveName":
				return StringUtil.capFirst(this.domainActiveName);
			case "lowerFirstDomainActiveName":
				return StringUtil.lowerFirst(this.domainActiveName);
			case "underLine":
				String underLine = StringUtil.changeDomainFieldtoTableColum(this.domainActiveName);
				if (underLine.contains("_")) return underLine;
				else return null;
			default: return null;				
		}
	}
	
	public List<TokenPair> genReplaceTokens(){
		List<TokenPair> results = new ArrayList<>();
		if (!StringUtil.isBlank(this.domainName)&&!StringUtil.isBlank(this.domainToken)) {
			String underLine = matchedToken("underLine");
			if (underLine!=null) {
				TokenPair underLinePair = new TokenPair(underLine,"StringUtil.changeDomainFieldtoTableColum(\"+"+this.domainToken+".getStandardName()+\")");
				results.add(underLinePair);
			}
			
			TokenPair capdomainPluralPair = new TokenPair(matchedToken("capFirstDomainPlural"),"\"+"+this.domainToken+".getCapFirstPlural()+\"");
			TokenPair lowerdomainPluralPair = new TokenPair(matchedToken("lowerFirstDomainPlural"),"\"+"+this.domainToken+".getLowerFirstPlural()+\"");
			results.add(capdomainPluralPair);
			results.add(lowerdomainPluralPair);
			if (!StringUtil.isBlank(this.domainNamingSuffix)) {
				TokenPair capFirstDomainNameWithSuffixPair = new TokenPair(matchedToken("capFirstDomainNameWithSuffix"),"\"+"+this.domainToken+".getCapFirstDomainNameWithSuffix()+\"");
				TokenPair lowerFirstDomainNameWithSuffixPair = new TokenPair(matchedToken("lowerFirstDomainNameWithSuffix"),"\"+"+this.domainToken+".getLowerFirstDomainNameWithSuffix()+\"");
				results.add(capFirstDomainNameWithSuffixPair);
				results.add(lowerFirstDomainNameWithSuffixPair);				
			}
			TokenPair capdomainNamePair = new TokenPair(matchedToken("capFirstDomainName"),"\"+"+this.domainToken+".getCapFirstDomainName()+\"");
			TokenPair lowerdomainNamePair = new TokenPair(matchedToken("lowerFirstDomainName"),"\"+"+this.domainToken+".getLowerFirstDomainName()+\"");
			results.add(capdomainNamePair);
			results.add(lowerdomainNamePair);

		}
		if (!StringUtil.isBlank(this.domainIdName)&&!StringUtil.isBlank(this.domainToken)) {
			TokenPair domainIdGetterPair = new TokenPair("get"+matchedToken("capFirstDomainIdName"),"\"+"+this.domainToken+".getDomainId().getGetterCallName()+\"");
			TokenPair domainIdSetterPair = new TokenPair("set"+matchedToken("capFirstDomainIdName"),"\"+"+this.domainToken+".getDomainId().getSetterCallName()+\"");
			results.add(domainIdGetterPair);
			results.add(domainIdSetterPair);
			TokenPair lowerFirstDomainIdPair = new TokenPair(matchedToken("lowerFirstDomainIdName"),"\"+"+this.domainToken+".getDomainId().getLowerFirstFieldName()+\"");
			results.add(lowerFirstDomainIdPair);
			
			String underLine = StringUtil.changeDomainFieldtoTableColum(this.domainIdName);
			if (underLine.contains("_")) {
				TokenPair underLinePair = new TokenPair(underLine,"StringUtil.changeDomainFieldtoTableColum(\"+"+this.domainToken+".getDomainId().getFieldNam()+\")");
				results.add(underLinePair);
			}
		}
		if (!StringUtil.isBlank(this.domainNameName)&&!StringUtil.isBlank(this.domainToken)) {
			TokenPair domainNameGetterPair = new TokenPair("get"+matchedToken("capFirstDomainNameName"),"\"+"+this.domainToken+".getDomainName().getGetterCallName()+\"");
			TokenPair domainNameSetterPair = new TokenPair("set"+matchedToken("capFirstDomainNameName"),"\"+"+this.domainToken+".getDomainName().getSetterCallName()+\"");
			results.add(domainNameGetterPair);
			results.add(domainNameSetterPair);
			TokenPair lowerFirstDomainNamePair = new TokenPair(matchedToken("lowerFirstDomainNameName"),"\"+"+this.domainToken+".getDomainName().getLowerFirstFieldName()+\"");
			results.add(lowerFirstDomainNamePair);
			
			String underLine = StringUtil.changeDomainFieldtoTableColum(this.domainNameName);
			if (underLine.contains("_")) {
				TokenPair underLinePair = new TokenPair(underLine,"StringUtil.changeDomainFieldtoTableColum(\"+"+this.domainToken+".getDomainName().getFieldNam()+\")");
				results.add(underLinePair);
			}
		}
		if (!StringUtil.isBlank(this.domainActiveName)&&!StringUtil.isBlank(this.domainToken)) {
			TokenPair activeGetterPair = new TokenPair("get"+matchedToken("capFirstDomainActiveName"),"\"+"+this.domainToken+".getActive().getGetterCallName()+\"");
			TokenPair activeIsGetterPair = new TokenPair("is"+matchedToken("capFirstDomainActiveName"),"\"+"+this.domainToken+".getActive().getGetterCallName()+\"");
			TokenPair activeSetterPair = new TokenPair("set"+matchedToken("capFirstDomainActiveName"),"\"+"+this.domainToken+".getActive().getSetterCallName()+\"");
			results.add(activeGetterPair);
			results.add(activeIsGetterPair);
			results.add(activeSetterPair);			
			
			TokenPair lowerFirstDomainActivePair = new TokenPair(matchedToken("lowerFirstDomainActiveName"),"\"+"+this.domainToken+".getActive().getLowerFirstFieldName()+\"");
			results.add(lowerFirstDomainActivePair);
			
			String underLine = StringUtil.changeDomainFieldtoTableColum(this.domainActiveName);
			if (underLine.contains("_")) {
				TokenPair underLinePair = new TokenPair(underLine,"StringUtil.changeDomainFieldtoTableColum(\"+"+this.domainToken+".getActive().getFieldNam()+\")");
				results.add(underLinePair);
			}
		}
		if (this.fields!=null&& this.fields.size()>0&&!StringUtil.isBlank(this.domainToken)) {
			for (String field:this.fields) {
				TokenPair lowerfieldGetterPair = new TokenPair("get"+StringUtil.capFirst(field),"\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.lowerFirst(field)+"\").getGetterCallName()+\"");
				TokenPair lowerisfieldGetterPair = new TokenPair("is"+StringUtil.capFirst(field),"\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.lowerFirst(field)+"\").getGetterCallName()+\"");
				TokenPair lowerfieldSetterPair = new TokenPair("set"+StringUtil.capFirst(field),"\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.lowerFirst(field)+"\").getSetterCallName()+\"");
				
				//TokenPair capfieldPair = new TokenPair(StringUtil.capFirst(field),"\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.capFirst(field)+"\").getCapFirstFieldName()+\"");
				TokenPair lowerfieldPair = new TokenPair(StringUtil.lowerFirst(field),"\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.lowerFirst(field)+"\").getLowerFirstFieldName()+\"");
				//results.add(capfieldPair);				
				results.add(lowerfieldGetterPair);
				results.add(lowerisfieldGetterPair);				results.add(lowerfieldSetterPair);
				results.add(lowerfieldPair);
				
				String underLine = StringUtil.changeDomainFieldtoTableColum(field);
				if (underLine.contains("_")) {
					TokenPair underLinePair = new TokenPair(underLine,"StringUtil.changeDomainFieldtoTableColum(\"+"+this.domainToken+".findFieldByFieldName(\""+StringUtil.lowerFirst(field)+"\").getFieldNam()+\")");
					results.add(underLinePair);
				}
			}
		}
		return results;
	}
	
	public String replaceAllTokens(String source,long serial,String first,String end,boolean completeMethod,boolean isFront,List<FakeDomain> validateList,boolean add100,boolean serialPrefix) {
		String [] statements = source.split("\n");
		StringBuilder sb = new StringBuilder();
		if (completeMethod) {
			if (isFront) {
				sb.append("FrontMethod method = new FrontMethod();\n")
				.append("method.setStandardName(\"add\"+StringUtil.capFirst(this.domain.getStandardName()));\n")
				.append("List<Writeable> sList = new ArrayList<Writeable>();\n");
			}else {
				sb.append("Method method = new Method();\n")
				.append("method.setStandardName(\"add\"+StringUtil.capFirst(this.domain.getStandardName()));\n")
				.append("List<Writeable> sList = new ArrayList<Writeable>();\n");	
			}
		}
		for (String s:statements) {
			s = s.replace("\"","\\\"");					
			List<TokenPair> pairs = new ArrayList<>();
			if (validateList == null || validateList.size()==0) pairs = this.genReplaceTokens();
			else {
				for (FakeDomain fd:validateList) {
					pairs.addAll(fd.genReplaceTokens());
				}
			}
			for (TokenPair tp:pairs) {
				s=s.replaceAll(tp.getSource(), tp.getTarget());
			}
			if (serialPrefix) {
				sb.append(first).append("serial+").append(serial).append("L,").append(countFrpmtSpaceTabs(s)).append(",\"").append(s.trim()).append(end).append("\n");
			}else {
				sb.append(first).append(serial).append("L,").append(countFrpmtSpaceTabs(s)).append(",\"").append(s.trim()).append(end).append("\n");
			}
			if (add100) serial += 100;
			else serial += 1000;
		}
		if (completeMethod) {
			sb.append("method.setMethodStatementList(WriteableUtil.merge(sList));\n");
			sb.append("return method;\n");
		}
		return sb.toString();
	}
	
	public String oldreplaceAllTokens(String source,long serial,String first,String end) {
		String [] statements = source.split("\n");
		String capDomainName = StringUtil.capFirst(domainName);
		String lowerDomainName = StringUtil.lowerFirst(capDomainName);
		String capPlural = StringUtil.capFirst(PluralUtil.lookupPlural(capDomainName));
		String lowerPlural = StringUtil.lowerFirst(capPlural);
		String capDomainNameWithSuffix = StringUtil.capFirst(domainName)+StringUtil.capFirst(domainNamingSuffix);
		String lowerDomainNameWithSuffix = StringUtil.lowerFirst(capDomainName)+StringUtil.capFirst(domainNamingSuffix);
		StringBuilder sb = new StringBuilder();

		for (String s:statements) {	
			s=s.replaceAll("\"", "\\\\\"");
			s=s.replaceAll(capPlural, "\"+this.domain.getCapFirstPlural()+\"");
			s=s.replaceAll(lowerPlural, "\"+this.domain.getLowerFi\rstPlural()+\"");
			s=s.replaceAll(capDomainName, "\"+this.domain.getCapFirstDomainName()+\"");
			s=s.replaceAll(lowerDomainName, "\"+this.domain.getLowerFirstDomainName()+\"");
			sb.append(first).append(serial).append("L,").append(countFrpmtSpaceTabs(s)).append(",\"").append(s.trim()).append(end).append("\n");
			serial += 1000;
		}
		return sb.toString();
	}
	
	private Integer countFrpmtSpaceTabs(String s) {
		Integer spaces = 0;
		for (int i=0;i<s.length();i++) {
			if (s.charAt(i)==' ') spaces += 1;
			else if (s.charAt(i)=='\t') spaces += 4;
			else break;
		}
		return (int)Math.ceil(spaces/4);
	}
	
	public void addField(String field) {
		this.fields.add(field);
	}
}
